package the.workshop.bu.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.util.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.wisteria.framework.web.BusinessException;
import org.wisteria.framework.web.QueryResult;
import the.workshop.bu.constant.CheckBizTypeEnum;
import the.workshop.bu.constant.CheckTypeEnum;
import the.workshop.bu.dto.*;
import the.workshop.bu.dto.req.MobileCheckConditionReq;
import the.workshop.bu.dto.req.MobileCheckExecuteReq;
import the.workshop.bu.entity.Check;
import the.workshop.bu.entity.Customer;
import the.workshop.bu.entity.CustomerTel;
import the.workshop.bu.mapper.MobileCheckMapper;
import the.workshop.bu.service.ICheckService;
import the.workshop.bu.service.ICustomerService;
import the.workshop.bu.service.ICustomerTelService;
import the.workshop.bu.service.IMobileCheckService;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class MobileCheckServiceImpl implements IMobileCheckService {

    @Resource
    private MobileCheckMapper mobileCheckMapper;

    @Resource
    private ICheckService checkService;

    @Resource
    private ICustomerTelService customerTelService;

    @Resource
    private ICustomerService customerService;

    @Override
    public QueryResult<MobileCheckDTO> pageList(MobileCheckConditionReq condition) {
        PageHelper.startPage(condition.getPageNum(), condition.getPageSize());
        Page page = mobileCheckMapper.selectListPage(condition);
        fillData(condition, page.getResult());
        return new QueryResult<>(page.getTotal(), page.getResult());
    }

    @Override
    public CheckDataDTO executeMobileCheck(MobileCheckExecuteReq req) {
        CheckDataDTO checkDataDTO = new CheckDataDTO();
        CustomerTelCondition condition = new CustomerTelCondition();
        condition.setIdList(req.getIdList());
        List<CustomerTelDTO> telList = customerTelService.listByCondition(condition);
        if (CollectionUtils.isEmpty(telList)) {
            return checkDataDTO;
        }

        List<Integer> customerIdList = telList.stream().map(CustomerTelDTO::getCustomerId).collect(Collectors.toList());
        Map<Integer, CustomerDTO> customerMap = selectCustomerMap(customerIdList);

        Map<String, Object> checkData = null;
        int dealTotal = 0;
        for (CustomerTelDTO tel : telList) {
            boolean isRemove = false;
            String mobile = tel.getTelNumber();
            if (!StringUtils.hasText(mobile) || mobile.length() != 11 || customerMap == null) {
                isRemove = true;
            } else {

                CustomerDTO customer = customerMap.get(tel.getCustomerId());
                if (customer == null) {
                    continue;
                }

                checkData = new HashMap<>();
                checkData.put("customerId", customer.getId());
                checkData.put("customerName", customer.getName());
                checkData.put("mobile", tel.getTelNumber());

                if (CheckTypeEnum.MOBILE_EMPTY.getValue() == req.getCheckType()) {
                    ServiceResult<MobileEmptyDTO> emptyResult = checkService.checkMobileEmpty(CheckBizTypeEnum.CUSTOMER, tel.getId(), mobile, checkData);
                    if (!emptyResult.getSuccess()) {
                        log.error("空号检测失败, Data: " + checkData.toString() + ", Result: " + emptyResult.toString());
                        throw BusinessException.withErrorCode("空号检测失败，" + emptyResult.getMsg());
                    }
                    MobileEmptyDTO mobileEmpty = (MobileEmptyDTO) emptyResult.getData();
                    if (mobileEmpty.getStatus().intValue() == 0 || mobileEmpty.getStatus().intValue() == 3) {
                        isRemove = true;
                    }
                } else if (CheckTypeEnum.MOBILE_NAME.getValue() == req.getCheckType()) {
                    if (!StringUtils.hasText(customer.getLegal())) {
                        continue;
                    }

                    checkData.put("legal", customer.getLegal());
                    ServiceResult<MobileNameDTO> mobileNameResult = checkService.checkMobileAndName(CheckBizTypeEnum.CUSTOMER, tel.getId(), mobile, customer.getLegal(), checkData);
                    if (!mobileNameResult.getSuccess()) {
                        log.error("二要素检测失败, Data: " + checkData.toString() + ", Result: " + mobileNameResult.toString());
                        int code = mobileNameResult.getCode().intValue();
                        if (code == 400 || code == 603 || code == 1001) {
                            throw BusinessException.withErrorCode("二要素检测失败，" + mobileNameResult.getMsg());
                        }
                        continue;
                    }

                    if (mobileNameResult.getData() != null && mobileNameResult.getData().getResult().intValue() == 0) {
                        setLegalTel(tel.getId());
                        setLegalStatus(tel.getCustomerId());
                        dealTotal++;
                    }
                }
            }

            if (isRemove) {
                customerTelService.removeById(tel.getId());
            }
        }
        checkDataDTO.setTotal(telList.size());
        checkDataDTO.setDealTotal(dealTotal);
        return checkDataDTO;
    }

    private Map<Integer, CustomerDTO> selectCustomerMap(List<Integer> idList) {
        CustomerCondition condition = new CustomerCondition();
        condition.setIdList(idList);
        List<CustomerDTO> customerList = customerService.listByCondition(condition);
        if (CollectionUtils.isEmpty(customerList)) {
            return null;
        }
        return customerList.stream().collect(Collectors.toMap(CustomerDTO::getId, e -> e));
    }

    private void fillData(MobileCheckConditionReq req, List<MobileCheckDTO> dataList) {
        if (CollectionUtils.isEmpty(dataList)) {
            return;
        }

        if (req.getCheckFlag() == 1) {
            // 已经检测
            List<Long> bizIdList = dataList.stream().map(e -> {return e.getId().longValue();}).collect(Collectors.toList());
            Map<Long, Check> checkMap = getMobileCheckInfo(req.getBizType(), req.getCheckType(), bizIdList);
            for (MobileCheckDTO dto : dataList) {
                Check check = checkMap.get(dto.getId().longValue());
                if (check == null) {
                    continue;
                }
                dto.setCheckTime(check.getCheckTime());
                dto.setCheckResult(check.getCheckResult());
            }
        }
    }

    private Map<Long, Check> getMobileCheckInfo(int bizType, int checkType, List<Long> bizIdList) {
        LambdaQueryWrapper<Check> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.in(Check::getBizId, bizIdList)
                .eq(Check::getBizType, bizType)
                .eq(Check::getCheckType, checkType)
                .eq(Check::getCheckStatus, 0);
        return checkService.list(queryWrapper).stream().collect(Collectors.toMap(Check::getBizId, e -> e, (k1, k2) -> k1));
    }

    private void setLegalTel(int id) {
        LambdaUpdateWrapper<CustomerTel> updateWrapper = new LambdaUpdateWrapper();
        updateWrapper.set(CustomerTel::getIsLegal, 1)
                .set(CustomerTel::getModifiedTime, new Date())
                .eq(CustomerTel::getId, id)
                .eq(CustomerTel::getIsDeleted, 0);
        customerTelService.update(updateWrapper);
    }

    private void setLegalStatus(int customerId) {
        LambdaUpdateWrapper<Customer> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(Customer::getStatus, "01001")
                .set(Customer::getModifiedTime, new Date())
                .set(Customer::getStatusTime, new Date())
                .eq(Customer::getId, customerId)
                .eq(Customer::getIsDeleted, 0);
        customerService.update(updateWrapper);
    }

}
